﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.StsAdmin;
using Microsoft.SharePoint;

namespace stsadm.ajaxifymoss
{
	public class AjaxifyMoss35 : ISPStsadmCommand
	{
		string _url = string.Empty;
		SPWebApplication _chosenWebApp = null;
		ConfigMode _configMode;

		private enum ConfigMode
		{
			Add,
			Remove
		}

		private struct ModifcationEntry
		{
			public string Name;
			public string Path;
			public string Value;
			public SPWebConfigModification.SPWebConfigModificationType ModType;

			public ModifcationEntry(string Name, string Path, string Value, SPWebConfigModification.SPWebConfigModificationType ModType)
			{
				this.Name = Name;
				this.Path = Path;
				this.Value = Value;
				this.ModType = ModType;
			}
		}

		#region ISPStsadmCommand Members

		public string GetHelpMessage(string command)
		{
			return "-url <URL of web application to ajaxify>";
		}

		public int Run(string command, System.Collections.Specialized.StringDictionary keyValues, out string output)
		{
			command = command.ToLowerInvariant();

			this._url = keyValues["url"];

			switch (command)
			{
				case "addajax35":
					this._configMode = ConfigMode.Add;
					addRemoveAjax();
					break;
				case "removeajax35":
					this._configMode = ConfigMode.Remove;
					addRemoveAjax();
					break;
				default:
					throw new InvalidOperationException();
			}

			output = "ASP.NET AJAX 3.5 configured successfully";

			return 0;
		}

		#endregion

		private void addRemoveAjax()
		{
			using (SPSite site = new SPSite(this._url))
			{
				this._chosenWebApp = site.WebApplication;
				addRemoveWebConfigMods();
			}
		}

		private void addRemoveWebConfigMods()
		{
			foreach (ModifcationEntry mod in getMods())
				addRemoveMod(mod);

			foreach (ModifcationEntry tagMod in getAspPageTagEntries())
				addRemoveMod(tagMod);

			this._chosenWebApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
			this._chosenWebApp.Update();
		}

		private void addRemoveMod(ModifcationEntry mod)
		{
			if (this._configMode == ConfigMode.Add)
				this._chosenWebApp.WebConfigModifications.Add(createModification(mod));
			else
				this._chosenWebApp.WebConfigModifications.Remove(createModification(mod));
		}

		private SPWebConfigModification createModification(ModifcationEntry modEntry)
		{
			SPWebConfigModification mod = new SPWebConfigModification(modEntry.Name, modEntry.Path);
			mod.Owner = "AjaxifyMOSS";
			mod.Sequence = 0;
			mod.Type = modEntry.ModType;
			mod.Value = modEntry.Value;
			return mod;
		}

		private List<ModifcationEntry> getMods()
		{
			List<ModifcationEntry> mods = new List<ModifcationEntry>();

			ModifcationEntry ajaxConfigSection = new ModifcationEntry();
			ajaxConfigSection.Name = "sectionGroup[@name='system.web.extensions']";
			ajaxConfigSection.Path = "configuration/configSections";
			ajaxConfigSection.Value = "" +
				"<sectionGroup name=\"system.web.extensions\" type=\"System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\">" +
				"<sectionGroup name=\"scripting\" type=\"System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\">" +
				  "<section name=\"scriptResourceHandler\" type=\"System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" allowDefinition=\"MachineToApplication\"/>" +
				  "<sectionGroup name=\"webServices\" type=\"System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\">" +
					"<section name=\"jsonSerialization\" type=\"System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" allowDefinition=\"Everywhere\" />" +
					"<section name=\"profileService\" type=\"System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" allowDefinition=\"MachineToApplication\" />" +
					"<section name=\"authenticationService\" type=\"System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" allowDefinition=\"MachineToApplication\" />" +
					"<section name=\"roleService\" type=\"System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" allowDefinition=\"MachineToApplication\" />" +
				  "</sectionGroup>" +
				"</sectionGroup>" +
			  "</sectionGroup>";
			ajaxConfigSection.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(ajaxConfigSection);

			ModifcationEntry SystemCore = new ModifcationEntry();
			SystemCore.Name = "add[@assembly='System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089']";
			SystemCore.Path = "configuration/system.web/compilation/assemblies";
			SystemCore.Value = "<add assembly=\"System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\"/>";
			SystemCore.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(SystemCore);

			ModifcationEntry SystemDataDataSetExtensions = new ModifcationEntry();
			SystemDataDataSetExtensions.Name = "add[@assembly='System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089']";
			SystemDataDataSetExtensions.Path = "configuration/system.web/compilation/assemblies";
			SystemDataDataSetExtensions.Value = "<add assembly=\"System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\"/>";
			SystemDataDataSetExtensions.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(SystemDataDataSetExtensions);

			ModifcationEntry SystemWebExtensions = new ModifcationEntry();
			SystemWebExtensions.Name = "add[@assembly='System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35']";
			SystemWebExtensions.Path = "configuration/system.web/compilation/assemblies";
			SystemWebExtensions.Value = "<add assembly=\"System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			SystemWebExtensions.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(SystemWebExtensions);

			ModifcationEntry SystemXmlLinq = new ModifcationEntry();
			SystemXmlLinq.Name = "add[@assembly='System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089']";
			SystemXmlLinq.Path = "configuration/system.web/compilation/assemblies";
			SystemXmlLinq.Value = "<add assembly=\"System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\"/>";
			SystemXmlLinq.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(SystemXmlLinq);

			ModifcationEntry asmxHandler = new ModifcationEntry();
			asmxHandler.Name = "add[@path='*.asmx']";
			asmxHandler.Path = "configuration/system.web/httpHandlers";
			asmxHandler.Value = "<add verb=\"*\" path=\"*.asmx\" validate=\"false\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			asmxHandler.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(asmxHandler);

			ModifcationEntry appServiceHandler = new ModifcationEntry();
			appServiceHandler.Name = "add[@path='*_AppService.axd']";
			appServiceHandler.Path = "configuration/system.web/httpHandlers";
			appServiceHandler.Value = "<add verb=\"*\" path=\"*_AppService.axd\" validate=\"false\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			appServiceHandler.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(appServiceHandler);

			ModifcationEntry scriptResourceHandler = new ModifcationEntry();
			scriptResourceHandler.Name = "add[@path='ScriptResource.axd']";
			scriptResourceHandler.Path = "configuration/system.web/httpHandlers";
			scriptResourceHandler.Value = "<add verb=\"GET,HEAD\" path=\"ScriptResource.axd\" type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" validate=\"false\"/>";
			scriptResourceHandler.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(scriptResourceHandler);

			ModifcationEntry scriptModule = new ModifcationEntry();
			scriptModule.Name = "add[@name='ScriptModule']";
			scriptModule.Path = "configuration/system.web/httpModules";
			scriptModule.Value = "<add name=\"ScriptModule\" type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			scriptModule.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(scriptModule);

			ModifcationEntry safeControl = new ModifcationEntry();
			safeControl.Name = "SafeControl[@Assembly='System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35']";
			safeControl.Path = "configuration/SharePoint/SafeControls";
			safeControl.Value = "<SafeControl Assembly=\"System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" Namespace=\"System.Web.UI\" TypeName=\"*\" Safe=\"True\" />";
			safeControl.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(safeControl);

			//the following dependent assembly entries were provided courtesy of 
			//Kyle Morris, Software Developer - Enterprise Solutions, for Custom House (http://www.customhouse.com)
			//Thanks Kyle!
			//ajaxifymoss35 is now completly automated

			ModifcationEntry dep1 = new ModifcationEntry();
			dep1.Name = "*[local-name()='dependentAssembly'][*/@name='System.Web.Extensions'][*/@publicKeyToken='31bf3856ad364e35'][*/@culture='neutral']";
			dep1.Path = "configuration/runtime/*[local-name()='assemblyBinding' and namespace-uri()='urn:schemas-microsoft-com:asm.v1']"; // filtering using the tag local name and namespace-uri
			dep1.Value = "" +
				"<dependentAssembly>" +
				"<assemblyIdentity name='System.Web.Extensions' publicKeyToken='31bf3856ad364e35' culture='neutral' />" +
				"<bindingRedirect oldVersion='1.0.0.0-1.1.0.0' newVersion='3.5.0.0' />" +
				"</dependentAssembly>";
			dep1.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(dep1);

			ModifcationEntry dep2 = new ModifcationEntry();
			dep2.Name = "*[local-name()='dependentAssembly'][*/@name='System.Web.Extensions.Design'][*/@publicKeyToken='31bf3856ad364e35'][*/@culture='neutral']";
			dep2.Path = "configuration/runtime/*[local-name()='assemblyBinding' and namespace-uri()='urn:schemas-microsoft-com:asm.v1']"; // filtering using the tag local name and namespace-uri
			dep2.Value = "" +
				"<dependentAssembly>" +
				"<assemblyIdentity name='System.Web.Extensions.Design' publicKeyToken='31bf3856ad364e35' culture='neutral' />" +
				"<bindingRedirect oldVersion='1.0.0.0-1.1.0.0' newVersion='3.5.0.0' />" +
				"</dependentAssembly>";
			dep2.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(dep2);
	
			ModifcationEntry systemWebExt = new ModifcationEntry();
			systemWebExt.Name = "system.web.extensions";
			systemWebExt.Path = "configuration";
			systemWebExt.Value = "" +
				"<system.web.extensions>" +
					"<scripting>" +
						"<webServices>" +
							"<!-- Uncomment this line to enable the authentication service. Include requireSSL=\"true\" if appropriate. -->" +
							"<!--" +
							"<authenticationService enabled=\"true\" requireSSL = \"true|false\"/>" +
							"-->" +
							"<!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and writeAccessProperties attributes. -->" +
							"<!--" +
							"<profileService enabled=\"true\"" +
							"readAccessProperties=\"propertyname1,propertyname2\"" +
							"writeAccessProperties=\"propertyname1,propertyname2\" />" +
							"-->" +
						"</webServices>" +
						"<!--" +
						"<scriptResourceHandler enableCompression=\"true\" enableCaching=\"true\" />" +
						"-->" +
					"</scripting>" +
				"</system.web.extensions>";
			systemWebExt.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(systemWebExt);

			ModifcationEntry sysWebServer = new ModifcationEntry();
			sysWebServer.Name = "system.webServer";
			sysWebServer.Path = "configuration";
			sysWebServer.Value = "" +
				"<system.webServer>" +
					"<validation validateIntegratedModeConfiguration=\"false\"/>" +
						"<modules>" +
							"<add name=\"ScriptModule\" preCondition=\"integratedMode\" type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"/>" +
						"</modules>" +
						"<handlers>" +
							"<remove name=\"WebServiceHandlerFactory-Integrated\" />" +
							"<add name=\"ScriptHandlerFactory\" verb=\"*\" path=\"*.asmx\" preCondition=\"integratedMode\" " +
								"type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>" +
							"<add name=\"ScriptHandlerFactoryAppServices\" verb=\"*\" path=\"*_AppService.axd\" preCondition=\"integratedMode\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>" +
							"<add name=\"ScriptResource\" preCondition=\"integratedMode\" verb=\"GET,HEAD\" path=\"ScriptResource.axd\" type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />" +
						"</handlers>" +
					"</system.webServer>";
			sysWebServer.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			mods.Add(sysWebServer);

			return mods;
		}

		private List<ModifcationEntry> getAspPageTagEntries()
		{
			List<ModifcationEntry> tagMods = new List<ModifcationEntry>();

			if (this._configMode == ConfigMode.Add)
			{
				ModifcationEntry controlsSection = new ModifcationEntry();
				controlsSection.Name = "controls";
				controlsSection.Path = "configuration/system.web/pages";
				controlsSection.Value = "<controls></controls>";//<add tagPrefix=\"asp\" namespace=\"System.Web.UI\" assembly=\"System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"/></controls>";
				controlsSection.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureSection;
				tagMods.Add(controlsSection);
			}

			ModifcationEntry SystemWebUI = new ModifcationEntry();
			SystemWebUI.Name = "add[@namespace='System.Web.UI']";
			SystemWebUI.Path = "configuration/system.web/pages/controls";
			SystemWebUI.Value = "<add tagPrefix=\"asp\" namespace=\"System.Web.UI\" assembly=\"System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			SystemWebUI.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			tagMods.Add(SystemWebUI);

			ModifcationEntry SystemWebUIWebControls = new ModifcationEntry();
			SystemWebUIWebControls.Name = "add[@namespace='System.Web.UI.WebControls']";
			SystemWebUIWebControls.Path = "configuration/system.web/pages/controls";
			SystemWebUIWebControls.Value = "<add tagPrefix=\"asp\" namespace=\"System.Web.UI.WebControls\" assembly=\"System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
			SystemWebUIWebControls.ModType = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
			tagMods.Add(SystemWebUIWebControls);

			return tagMods;
		}
	}
}
